package com.tim.app.record.view;

import android.content.Context;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.os.Handler.Callback;
import android.os.Message;

import com.application.library.log.DLOG;
import com.tim.app.record.Pcm2Wav;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;


/**
 * 录音和写入文件使用了两个不同的线程，以免造成卡机现象
 * 录音波形绘制
 *
 * @author tcx
 */
public class RecordUtil {

    private ArrayList<Short> inBuf = new ArrayList<Short>();//缓冲区数据
    private ArrayList<byte[]> write_data = new ArrayList<byte[]>();//写入文件数据
    public boolean isRecording = false;// 录音线程控制标记
    private boolean isWriting = false;// 录音线程控制标记

    public int rateX = 30;//控制多少帧取一帧

    private AudioRecord audioRecord;
    int recBufSize;
    private int draw_time = 1000 / 200;//两次绘图间隔的时间
    private float divider = 0.2f;//为了节约绘画时间，每0.2个像素画一个数据
    long c_time;
    private String savePcmPath;//保存pcm文件路径
    private String saveWavPath;//保存wav文件路径
    private Context mContext;
    private int readsize;

    private boolean isPause = false;

    /**
     * 开始录音
     *
     * @param audioRecord
     * @param recBufSize
     * @param audioName
     */
    public void Start(AudioRecord audioRecord, int recBufSize
            , String audioName, String path, Callback callback, Context context) {
        this.audioRecord = audioRecord;
        isRecording = true;
        isWriting = true;
        this.recBufSize = recBufSize;
        savePcmPath = path + audioName + ".pcm";
        saveWavPath = path + audioName + ".wav";
        this.mContext = context;
        new Thread(new WriteRunnable()).start();//开线程写文件
        new RecordTask(audioRecord, recBufSize, callback).execute();
    }

    /**
     * 停止录音
     */
    public void Stop() {
        isRecording = false;
        isPause = true;
        audioRecord.stop();
    }

    /**
     * pause recording audio
     */
    public void pause() {
        isPause = true;
    }


    /**
     * restart recording audio
     */
    public void reStart() {
        isPause = false;
    }


    /**
     * 清楚数据
     */
    public void clear() {
        inBuf.clear();// 清除
    }


    /**
     * 异步录音程序
     *
     * @author cokus
     */
    class RecordTask extends AsyncTask<Object, Object, Object> {
        private int recBufSize;
        private AudioRecord audioRecord;
        private Callback callback;
        private int cAmplitude = 0;

        public RecordTask(AudioRecord audioRecord, int recBufSize, Callback callback) {
            this.audioRecord = audioRecord;
            this.recBufSize = recBufSize;
            this.callback = callback;
            inBuf.clear();// 清除  
        }

        @Override
        protected Object doInBackground(Object... params) {
            try {
                short[] buffer = new short[recBufSize];
                audioRecord.startRecording();// 开始录制
                while (isRecording) {

                    while (!isPause) {
                        // 从MIC保存数据到缓冲区  
                        readsize = audioRecord.read(buffer, 0,
                                recBufSize);
                        synchronized (inBuf) {
                            for (int i = 0; i < readsize; i += rateX) {
                                inBuf.add(buffer[i]);
                            }
                        }
                        long v = 0;
                        // 将 buffer 内容取出。进行平方和运算
                        for (int i = 0; i < buffer.length; i++) {
                            v += buffer[i] * buffer[i];
                        }
                        // 平方和除以数据总长度，得到音量大小。
                        double mean = v / (double) readsize;
                        double volume = 10 * Math.log10(mean);
                        Message msg = new Message();
                        msg.arg1 = (int) volume;
                        callback.handleMessage(msg);
                        DLOG.e("===", "arg==" + volume);

                        publishProgress();//更新主线程中的UI
                        if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
                            synchronized (write_data) {
                                byte bys[] = new byte[readsize * 2];
                                //因为arm字节序问题，所以需要高低位交换
                                for (int i = 0; i < readsize; i++) {
                                    byte ss[] = getBytes(buffer[i]);
                                    bys[i * 2] = ss[0];
                                    bys[i * 2 + 1] = ss[1];
                                }
                                write_data.add(bys);
                            }
                        }
                    }
                }
                isWriting = false;

            } catch (Throwable t) {
                Message msg = new Message();
                msg.arg1 = -2;
                msg.obj = t.getMessage();
                callback.handleMessage(msg);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Object... values) {
            long time = new Date().getTime();
            if (time - c_time >= draw_time) {
                ArrayList<Short> buf = new ArrayList<Short>();
                synchronized (inBuf) {
                    if (inBuf.size() == 0)
                        return;
                    buf = (ArrayList<Short>) inBuf.clone();// 保存
                }

                int mVolume = calculateRealVolume(buf, buf.size());
                Message msg = new Message();
                msg.arg1 = mVolume;
//                callback.handleMessage(msg);
                c_time = new Date().getTime();
            }
            super.onProgressUpdate(values);
        }

        /**
         * 此计算方法来自samsung开发范例
         *
         * @param buffer
         * @param readSize
         */
        private int calculateRealVolume(ArrayList<Short> buffer, int readSize) {
            int mVolume = 0;
            int sum = 0;
            for (int i = 0; i < readSize; i++) {
                sum += buffer.get(i) * buffer.get(i);
            }
            double mean = sum / (double) readsize;
            mVolume = (int) (10 * Math.log10(mean));
            return mVolume;
        }

        public byte[] getBytes(short s) {
            byte[] buf = new byte[2];
            for (int i = 0; i < buf.length; i++) {
                buf[i] = (byte) (s & 0x00ff);
                s >>= 8;
            }
            return buf;
        }
    }

    /**
     * 异步写文件
     *
     * @author cokus
     */
    class WriteRunnable implements Runnable {
        @Override
        public void run() {
            try {
                FileOutputStream fos2wav = null;
                File file2wav = null;
                try {
                    file2wav = new File(savePcmPath);
                    if (file2wav.exists()) {
                        file2wav.delete();
                    } else {
                        file2wav.createNewFile();
                    }
                    fos2wav = new FileOutputStream(file2wav);// 建立一个可存取字节的文件
                } catch (Exception e) {
                    e.printStackTrace();
                }
                while (isWriting || write_data.size() > 0) {

                    byte[] buffer = null;
                    synchronized (write_data) {
                        if (write_data.size() > 0) {
                            buffer = write_data.get(0);
                            write_data.remove(0);
                        }
                    }
                    try {
                        if (buffer != null) {
                            fos2wav.write(buffer);
                            fos2wav.flush();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                fos2wav.close();
                Pcm2Wav p2w = new Pcm2Wav();//将pcm格式转换成wav 其实就尼玛加了一个44字节的头信息
                p2w.convertAudioFiles(savePcmPath, saveWavPath);
            } catch (Throwable t) {
            }
        }
    }


}   
